package device;

import base.UsersBaseInterface;
import device.callbacks.VerifyOnce;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;

public abstract class Device {
    // UsersBase 支持
    protected UsersBaseInterface users;
    // 绑定一个用户名
    protected String userNameBundle = null;
    // 设备的 ID 编号
    protected String deviceID;
    // 设备是否更新？
    protected boolean updateFlag;
    // 该设备的通信接口
    private final SocketChannel socketChannel;
    // 设备的数据键值
    protected HashMap<String, String> keys;
    // 订阅集合
    protected final HashSet<Device> subscribeSet;

    public Device(SocketChannel socketChannel, UsersBaseInterface users) {
        this.users = users;
        this.socketChannel = socketChannel;
        this.subscribeSet = new HashSet<>();
        this.updateFlag = false;
    }

    public abstract boolean subscribe(Device targetDevice, VerifyOnce verify);

    public abstract void update(HashMap<String, String> msgsSet) throws IOException;

    public String getDeviceID() {
        return deviceID;
    }

    public void bundleUserName(String userNameBundle) { this.userNameBundle = userNameBundle; }

    public void setDeviceID(String deviceID) {
        this.deviceID = deviceID;
    }

    public void registerKeysDict(HashMap<String, String> dict) {
        this.keys = dict;
    }

    protected void addSubscriber(Device subscriber) {
        subscribeSet.add(subscriber);
        this.updateFlag = true;
    }

    private void removeSubscriber(Device subscriber) {
        subscribeSet.remove(subscriber);
    }

    public void subscribe(Device targetDevice) {
        if (targetDevice != null) {
            targetDevice.addSubscriber(this);
        }
    }

    public void unSubscribe(Device targetDevice) {
        if (targetDevice != null) {
            targetDevice.removeSubscriber(this);
        }
    }

    protected void sendBuffer(ByteBuffer buffer) throws IOException {
        socketChannel.write(buffer);
    }

    public void simpleSend(String message) throws IOException {
        ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
        sendBuffer(buffer);
    }

    public void afterRegisterCall() {
    }

    /**
     * 发布一条消息
     * @param collects 将会发布的参数集
     * @throws IOException IO错误
     */
    public void publish(Collection<String> collects) throws IOException {
        if (!updateFlag) {
            return;
        }

        StringBuilder buffer = new StringBuilder();

        //buffer.append("devID=").append(deviceID);

        boolean flag = false;
        for (String key : collects) {
            if (flag) {
                buffer.append(",");
            }
            String value = keys.get(key);
            if (value != null) {
                buffer.append(key).append("=").append(keys.get(key));
            } else {
                continue;
            }
            flag = true;
        }

        // 将消息转发给订阅者
        for (Device dev : subscribeSet) {
            ByteBuffer message = ByteBuffer.wrap(buffer.toString().getBytes());
            try {
                dev.sendBuffer(message);
            } catch (IOException e) {
                /* 不能向设备发送消息，则取消该设备的订阅 */
                dev.unSubscribe(this);
            }
            updateFlag = false;
        }
    }
}
